#pragma once

// 文件版本
#include <unordered_map>
#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
#include <cassert>

#include "../comm/util.hpp"
#include "../comm/log.hpp"

// model 主要负责处理与数据的交互，比如增删改查
namespace ns_model
{
    using namespace std;
    using namespace ns_util;
    using namespace ns_log;
    // 描述题目结构体
    struct Question
    {
        string number; // 题目标号
        string title;  // 题目标题
        string grade;  // 分为简单 中等 困难
        int cpu_limit; // 时间限制
        int mem_limit; // 空间限制
        string desc;   // 具体描述
        string header; // 提供给用户的预设代码
        string tail;   // 测试用例，最后拼接用户代码，形成完整代码代码
    };

    const string question_list_path = "./questions/questions.list";
    const string question_path = "./questions/";
    class Model
    {
    public:
        Model()
        {
            assert(LoadQuestionList(question_list_path));
            LOG(INFO) << "题目配置文件: " << question_list_path << ",加载成功" << std::endl;
        }
        // 加载题目到内存构建映射关系
        bool LoadQuestionList(const string &_question_list_path)
        {
            ifstream in(_question_list_path);
            if (!in.is_open())
            {
                LOG(FATAL) << "题目配置文件: " << _question_list_path << "加载失败" << std::endl;
                return false;
            }
            string line;
            while (getline(in, line))
            {
                vector<string> result;
                StringUtil::SplitString(line, &result, " ");
                if (result.size() != 5)
                {
                    LOG(WARNING) << "题目配置文件不完整！" << std::endl;
                    continue;
                }
                Question q;
                q.number = result[0];
                q.title = result[1];
                q.grade = result[2];
                q.cpu_limit = atoi(result[3].c_str());
                q.mem_limit = atoi(result[4].c_str());

                // 构建文件名读取文件
                //./questions/number/...
                string path = question_path;
                path += q.number;
                path += "/";
                FileUtil::ReadFile(path + "desc.txt", &(q.desc), true);
                FileUtil::ReadFile(path + "header.cpp", &(q.header), true);
                FileUtil::ReadFile(path + "tail.cpp", &(q.tail), true);
                // 构建映射关系
                _questions[q.number] = q;
            }
            // 关闭文件
            in.close();
            return true;
        }
        // 查看题目列表
        bool GetAllQuestions(vector<Question> *out)
        {
            out->clear();
            for (auto &q : _questions)
            {
                out->push_back(q.second);
            }

            //获取题目以后进行排序
            sort(out->begin(), out->end(), [](const Question &q1, const Question &q2)
                 { return atoi(q1.number.c_str()) < atoi(q2.number.c_str()); });
                 
            return true;
        }
        // 查看指定题目
        bool GetOneQuestion(string number, Question *q)
        {
            auto item = _questions.find(number);
            if (item == _questions.end())
            {
                return false;
            }
            (*q) = item->second;
            return true;
        }
        ~Model()
        {
        }

    private:
        // 构建题号和题目的映射关系
        unordered_map<string, Question> _questions;
    };
}